﻿<!--
> Muaz Khan     - https://github.com/muaz-khan
> MIT License   - https://www.webrtc-experiment.com/licence/
> Documentation - https://github.com/muaz-khan/WebRTC-Experiment/tree/master/socket.io
-->
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Socket.io | WebRTC One-to-One Video Chat</title>

        <script>
            if(!location.hash.replace('#', '').length) {
                location.href = location.href.split('#')[0] + '#' + (Math.random() * 100).toString().replace('.', '');
                location.reload();
            }
        </script>
        
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
        <link rel="author" type="text/html" href="https://plus.google.com/+MuazKhan">
        <meta name="author" content="Muaz Khan">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <link rel="stylesheet" href="https://www.webrtc-experiment.com/style.css">

        <style>
            audio, video {
                -moz-transition: all 1s ease;
                -ms-transition: all 1s ease;

                -o-transition: all 1s ease;
                -webkit-transition: all 1s ease;
                transition: all 1s ease;
                vertical-align: top;
            }

            input {
                border: 1px solid #d9d9d9;
                border-radius: 1px;
                font-size: 2em;
                margin: .2em;
                width: 30%;
            }

            .setup {
                border-bottom-left-radius: 0;
                border-top-left-radius: 0;
                font-size: 102%;
                height: 47px;
                margin-left: -9px;
                margin-top: 8px;
                position: absolute;
            }

            p { padding: 1em; }

            li {
                border-bottom: 1px solid rgb(189, 189, 189);
                border-left: 1px solid rgb(189, 189, 189);
                padding: .5em;
            }

            .highlight { color: rgb(0, 8, 189); }
        </style>
        <script>
            document.createElement('article');
            document.createElement('footer');
        </script>

        <!-- scripts used for peers connection -->
        <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
        <script src="https://www.webrtc-experiment.com/socket.io.js"> </script>
        <script src="https://www.webrtc-experiment.com/IceServersHandler.js"></script>
        <script src="https://www.webrtc-experiment.com/socket.io/PeerConnection.js"> </script>
    </head>

    <body>
        <article>
            <header style="text-align: center;">
                <h1>
                    Socket.io | WebRTC One-to-One Video Chat
                </h1>
                <p>
                    <a href="https://www.webrtc-experiment.com/">HOME</a>
                    <span> &copy; </span>
                    <a href="http://www.MuazKhan.com/" target="_blank">Muaz Khan</a>

                    .
                    <a href="http://twitter.com/WebRTCWeb" target="_blank" title="Twitter profile for WebRTC Experiments">@WebRTCWeb</a>

                    .
                    <a href="https://github.com/muaz-khan?tab=repositories" target="_blank" title="Github Profile">Github</a>

                    .
                    <a href="https://github.com/muaz-khan/WebRTC-Experiment/issues?state=open" target="_blank">Latest issues</a>

                    .
                    <a href="https://github.com/muaz-khan/WebRTC-Experiment/commits/master" target="_blank">What's New?</a>
                </p>
            </header>

            <div class="github-stargazers"></div>

            <!-- just copy this <section> and next script -->
            <section class="experiment">
                <section>
                    <span>
                        Private ?? <a href="/socket.io/" target="_blank" title="Setup Private Room!"><code><strong id="unique-token">#123456789</strong></code></a>
                    </span>
                    <input type="text" id="your-name" placeholder="your-name">
                    <button id="start-broadcasting" class="setup">Start Transmitting Yourself!</button>
                </section>

                <!-- list of all available conferencing rooms -->
                <table id="rooms-list" style="width: 100%;"></table>

                <!-- local/remote videos container -->
                <div id="videos-container"></div>
            </section>

            <script>
                // Muaz Khan     - https://github.com/muaz-khan
                // MIT License   - https://www.webrtc-experiment.com/licence/
                // Documentation - https://github.com/muaz-khan/WebRTC-Experiment/tree/master/socket.io

                var channel = location.href.replace(/\/|:|#|%|\.|\[|\]/g, '');
                var sender = Math.round(Math.random() * 999999999) + 999999999;

                var SIGNALING_SERVER = 'https://socketio-over-nodejs2.herokuapp.com:443/';
                io.connect(SIGNALING_SERVER).emit('new-channel', {
                    channel: channel,
                    sender: sender
                });

                var socket = io.connect(SIGNALING_SERVER + channel);
                socket.on('connect', function () {
                    // setup peer connection & pass socket object over the constructor!
                });

                socket.send = function (message) {
                    socket.emit('message', {
                        sender: sender,
                        data: message
                    });
                };

                // var peer = new PeerConnection('http://socketio-signaling.jit.su:80');
                var peer = new PeerConnection(socket);
                peer.onUserFound = function(userid) {
                    if (document.getElementById(userid)) return;
                    var tr = document.createElement('tr');

                    var td1 = document.createElement('td');
                    var td2 = document.createElement('td');

                    td1.innerHTML = userid + ' has camera. Are you interested in video chat?';

                    var button = document.createElement('button');
                    button.innerHTML = 'Join';
                    button.id = userid;
                    button.style.float = 'right';
                    button.onclick = function() {
                        button = this;
                        getUserMedia(function(stream) {
                            peer.addStream(stream);
                            peer.sendParticipationRequest(button.id);
                        });
                        button.disabled = true;
                    };
                    td2.appendChild(button);

                    tr.appendChild(td1);
                    tr.appendChild(td2);
                    roomsList.appendChild(tr);
                };

                peer.onStreamAdded = function(e) {
                    var video = e.mediaElement;
                    video.setAttribute('width', 600);
                    videosContainer.insertBefore(video, videosContainer.firstChild);

                    video.play();
                    rotateVideo(video);
                    scaleVideos();
                };

                peer.onStreamEnded = function(e) {
                    var video = e.mediaElement;
                    if (video) {
                        video.style.opacity = 0;
                        rotateVideo(video);
                        setTimeout(function() {
                            video.parentNode.removeChild(video);
                            scaleVideos();
                        }, 1000);
                    }
                };

                document.querySelector('#start-broadcasting').onclick = function() {
                    this.disabled = true;
                    getUserMedia(function(stream) {
                        peer.addStream(stream);
                        peer.startBroadcasting();
                    });
                };

                document.querySelector('#your-name').onchange = function() {
                    peer.userid = this.value;
                };

                var videosContainer = document.getElementById('videos-container') || document.body;
                var btnSetupNewRoom = document.getElementById('setup-new-room');
                var roomsList = document.getElementById('rooms-list');

                if (btnSetupNewRoom) btnSetupNewRoom.onclick = setupNewRoomButtonClickHandler;

                function rotateVideo(video) {
                    video.style[navigator.mozGetUserMedia ? 'transform' : '-webkit-transform'] = 'rotate(0deg)';
                    setTimeout(function() {
                        video.style[navigator.mozGetUserMedia ? 'transform' : '-webkit-transform'] = 'rotate(360deg)';
                    }, 1000);
                }

                function scaleVideos() {
                    var videos = document.querySelectorAll('video'),
                        length = videos.length, video;

                    var minus = 130;
                    var windowHeight = 700;
                    var windowWidth = 600;
                    var windowAspectRatio = windowWidth / windowHeight;
                    var videoAspectRatio = 4 / 3;
                    var blockAspectRatio;
                    var tempVideoWidth = 0;
                    var maxVideoWidth = 0;

                    for (var i = length; i > 0; i--) {
                        blockAspectRatio = i * videoAspectRatio / Math.ceil(length / i);
                        if (blockAspectRatio <= windowAspectRatio) {
                            tempVideoWidth = videoAspectRatio * windowHeight / Math.ceil(length / i);
                        } else {
                            tempVideoWidth = windowWidth / i;
                        }
                        if (tempVideoWidth > maxVideoWidth)
                            maxVideoWidth = tempVideoWidth;
                    }
                    for (var i = 0; i < length; i++) {
                        video = videos[i];
                        if (video)
                            video.width = maxVideoWidth - minus;
                    }
                }

                window.onresize = scaleVideos;

                // you need to capture getUserMedia yourself!
                function getUserMedia(callback) {
                    var hints = {audio:true,video:{
                        optional: [],
                        mandatory: {}
                    }};
                    navigator.getUserMedia(hints,function(stream) {
                        var video = document.createElement('video');
                        video.srcObject = stream;
                        video.controls = true;
                        video.muted = true;

                        peer.onStreamAdded({
                            mediaElement: video,
                            userid: 'self',
                            stream: stream
                        });

                        callback(stream);
                    });
                }

                (function() {
                    var uniqueToken = document.getElementById('unique-token');
                    if (uniqueToken)
                        if (location.hash.length > 2) uniqueToken.parentNode.parentNode.parentNode.innerHTML = '<h2 style="text-align:center;"><a href="' + location.href + '" target="_blank">Share this link</a></h2>';
                        else uniqueToken.innerHTML = uniqueToken.parentNode.parentNode.href = '#' + (Math.random() * new Date().getTime()).toString(36).toUpperCase().replace( /\./g , '-');
                })();

            </script>

            <section class="experiment">
                <ol>
                    <li>Using socket.io (over node.js) for signaling</li>
                    <li>It is one-to-one peers connection</li>
                </ol>
            </section>

            <section class="experiment">
                <h2 class="header">How to use PeerConnection.js?</h2>
                <pre>
// http://www.webrtc-experiment.com/socket.io/PeerConnection.js

var peer = new <strong>PeerConnection</strong>('<strong class="highlight">http://domain:port</strong>');
peer.<strong title="local or remote stream">onStreamAdded</strong> = function(e) {
   document.body.appendChild(e.mediaElement);
};

// the easiest method of "manual" peers connection is
// call "sendParticipationRequest" and pass user-id of the target user
peer.<strong>sendParticipationRequest</strong>(userid);

// <u>otherwise</u>, call "startBroadcasting"
// (behind the scene) this function will be invoked
// recursively until a participant found
peer.<strong>startBroadcasting</strong>();
</pre>
            </section>

            <section class="experiment">
                <h2 class="header">Simplest Demo</h2>
                <pre>
var offerer = new <strong title="Constructor takes three arguments.
1) websocket url
2) socket event and
3) custom user-id">PeerConnection</strong>('<strong class="highlight" title="websocket url">http://domain:port</strong>', '<strong class="highlight" title="socket event to emit/receive messages">message</strong>', '<strong class="highlight" title="custom user-id">offerer</strong>');
offerer.<strong title="local or remote stream">onStreamAdded</strong> = function(e) {
   document.body.appendChild(e.mediaElement);
};
</pre>

                <pre>
var answerer = new <strong title="Constructor takes three arguments.
1) websocket url
2) socket event and
3) custom user-id">PeerConnection</strong>('<strong class="highlight" title="websocket url">http://domain:port</strong>', '<strong class="highlight" title="socket event to emit/receive messages">message</strong>', '<strong class="highlight" title="custom user-id">answerer</strong>');
answerer.<strong title="local or remote stream">onStreamAdded</strong> = function(e) {
   document.body.appendChild(e.mediaElement);
};
answerer.<strong title="Ask other user to establish peer connection with you!">sendParticipationRequest</strong>(<strong class="highlight" title="user-id of the offerer">'offerer'</strong>);
</pre>
            </section>

            <section class="experiment">
                <h2 class="header" id="signaling">getUserMedia is "in-your-own-hands"!</h2>
                <p>
                    It is upto you to decide when to capture the stream; how to capture; and the quality of the stream.
                </p>
                <pre>
function getUserMedia(callback) {
    var hints = {
        audio: true,
        video: {
            optional: [],

            // capture super-hd stream!
            mandatory: {
                minWidth: 1280,
                minHeight: 720,
                maxWidth: 1920,
                maxHeight: 1080,
                minAspectRatio: 1.77
            }
        }
    };

    navigator.getUserMedia(hints, function (stream) {
        //    you can use "peer.addStream" to attach stream
        //    peer.addStream(stream);
        // or peer.MediaStream = stream;

        callback(stream);

        // preview local video
        var video = document.createElement('video');
        video.srcObject = stream;
        video.controls = true;
        video.muted = true;

        peer.onStreamAdded({
            mediaElement: video,
            userid: 'self',
            stream: stream
        });
    });
}
</pre>
            </section>

            <section class="experiment">
                <h2 class="header" id="signaling">Want to use <a href="https://github.com/muaz-khan/WebRTC-Experiment/tree/master/socketio-over-nodejs" target="_blank">Socket.io over Node.js</a>?</h2>
                <pre>
var channel = location.href.replace(/\/|:|#|%|\.|\[|\]/g, '');
var sender = Math.round(Math.random() * 999999999) + 999999999;

// var SIGNALING_SERVER = 'https://socketio-over-nodejs2.herokuapp.com:443/';
var SIGNALING_SERVER = 'https://webrtcweb.com:9559/';
io.connect(SIGNALING_SERVER).emit('new-channel', {
    channel: channel,
    sender: sender
});

var socket = io.connect(SIGNALING_SERVER + channel);
socket.send = function (message) {
    socket.emit('message', {
        sender: sender,
        data: message
    });
};

// pass "socket" object over the constructor instead of URL
var peer = new PeerConnection(socket);
</pre>

            <p>
                Check <a href="https://github.com/muaz-khan/WebRTC-Experiment/blob/master/Signaling.md" target="_blank">other signaling examples</a>.
            </p>
            </section>

            <section class="experiment own-widgets latest-commits">
                <h2 class="header" id="updates" style="color: red; padding-bottom: .1em;"><a href="https://github.com/muaz-khan/WebRTC-Experiment/commits/master" target="_blank">Latest Updates</a></h2>
                <div id="github-commits"></div>
            </section>

            <section class="experiment">
                <h2 class="header" id="feedback">Feedback</h2>
                <div>
                    <textarea id="message" style="border: 1px solid rgb(189, 189, 189); height: 8em; margin: .2em; outline: none; resize: vertical; width: 98%;" placeholder="Have any message? Suggestions or something went wrong?"></textarea>
                </div>
                <button id="send-message" style="font-size: 1em;">Send Message</button><small style="margin-left: 1em;">Enter your email too; if you want "direct" reply!</small>
            </section>
        </article>

        <a href="https://github.com/muaz-khan/WebRTC-Experiment/tree/master/socket.io" class="fork-left"></a>

        <footer>
            <p>
                <a href="https://www.webrtc-experiment.com/">WebRTC Experiments</a>
                © <a href="https://plus.google.com/+MuazKhan" rel="author" target="_blank">Muaz Khan</a>
                <a href="mailto:muazkh@gmail.com" target="_blank">muazkh@gmail.com</a>
            </p>
        </footer>

        <!-- commits.js is useless for you! -->
        <script src="https://www.webrtc-experiment.com/commits.js" async> </script>
    </body>
</html>
